<!DOCTYPE html>
<html>
<head>
    <title>PHP大文件分片上传</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<style type="text/css">
    #percent-bg{position:relative;width:10%;height:20px;border:1px solid #ccc;}
    #percent{position:absolute;display:block;width:0;height:100%;left:0;background:green;z-index:100;}
    #percent_num{position:absolute;display:block;width:30px;height:100%;left:50%;margin-left:-15px;z-index:200; text-align:center;}
</style>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.js"></script>
<script type="text/javascript">
    var pz = {
        "maxSize":1024*1024*20000, //文件大小限制200M
        "bufferSize":1024*512, //单个分片大小
        "blocks":[], //分片数据集合
        "blockName":"newfile",//表单 file 的名字
        "filename":"",//上传的本地文件真实文件名
        "threadNum":2,//上传线程数量
        "reset":function(fname){
            this.blocks = [];
            this.filename = fname;
        }
    }
    function afterselect(){
        if(document.getElementById("x").files.length<1){
            return false;
        }
        var file = document.getElementById("x").files[0];
        if(file.size>pz.maxSize){
            showmsg("文件大小限制："+pz.maxSize+"，实际文件大小："+file.size);
            return;
        }
        pz.reset(file.name);
        pz.threadNum = parseInt($("#threadCount").val());//设定线程数量


        __index = __activeThreadCount = __sendedBlockCount = 0;

        var endByte = 0,startByte = 0;

        while(true){
            startByte = endByte;
            if(endByte + pz.bufferSize >= file.size){
                endByte = file.size;
            }else{
                endByte = endByte+pz.bufferSize;
            }
            var block = sliceFile(file,startByte,endByte);
            if(!block){
                showmsg("分片失败");
                return;
            }
            pz.blocks.push(block);
            if(endByte >= file.size){ break; }
        }
        console.log("文件名："+file.name);
        console.log("文件大小："+file.size);
        console.log("总分片数量："+pz.blocks.length);
        var dis = Math.min(pz.threadNum,pz.blocks.length);
        for(var i=0;i<dis;i++){
            (function(i){
                setTimeout(function(){
                    __activeThreadCount++;
                    fenpei(i);
                },500);
            })(i);
        }
        console.log("启动线程："+dis+" 个");
        console.log("------------------------");
    }

    //只要是操作主线程中的变量或其他，就一定会自动同步到主线程来。相当于自动lock()
    var __index = 0;
    var __activeThreadCount = 0; //当前活跃线程数量
    var __sendedBlockCount = 0; //已上传的block数量
    var time = new Date(); //此次上传辅助标识
    function fenpei(i){
        //参数:线程名
        if(__index>=pz.blocks.length){
            console.log("线程"+i+' 结束');
            __activeThreadCount--;
            if(__activeThreadCount==0){
                console.log("------------------------");
                console.log('多线程分片上传完毕，正在处理分片数据...');
                combineFile();
            }
            return;
        }
        uploadBlock(i,__index);
        __index++;
    }
    //发送拼接分块命令
    function combineFile(){
        $.post(
            '<?= url('dividend.system/uploadFile') ?>',
            {"act":"combine","chunks":pz.blocks.length,"filename":pz.filename,"time":time},
            function(e){
                console.log(e);
                if(e.flag){
                    showmsg("分片数据处理完成，任务结束");
                }else{
                    showmsg('拼接失败');
                }
            },'json'
        );
    }
    //显示进度
    function showPercent(){
        var percent = parseInt(__sendedBlockCount / pz.blocks.length *100);
        if(percent>100){ percent = 100;	}
        $("#percent").stop(true,true).animate({"width":percent+"%"},10);
        $("#percent_num").html(percent+"%");
    }
    //上传一个分片
    function uploadBlock(i,index){
        var chunk = index;
        var fd = new FormData();
        fd.append("newfile", pz.blocks[chunk]);//文件
        fd.append("filename", pz.filename);//文件名
        fd.append("chunk", chunk);//分片索引
        fd.append("chunks", pz.blocks.length);//分片总数
        fd.append("time", time);//分片总数
        $.ajax({
            url:'<?= url('dividend.system/uploadFile') ?>',
            type:"post",
            data: fd,
            dataType:"json",
            cache: false,
            contentType:false,
            processData:false,//设置为true的时候,jquery ajax 提交的时候不会序列化 data，而是直接使用data
            success:function(data){
                //timer线程中的异步，此时同步了
                __sendedBlockCount++;
                showPercent();
                fenpei(i);
            },
            complete:function(XMLHttpRequest,textStatus){
            },
            error:function(){}
        });
    }
    //分割file成分片
    function sliceFile(file,startByte,endByte){
        if(file.slice){
            return  file.slice(startByte,endByte);
        }
        if(file.webkitSlice){
            return  file.webkitSlice(startByte,endByte);
        }
        if(file.mozSlice){
            return  file.mozSlice(startByte,endByte);
        }
        return null;
    }
    //输出消息
    function showmsg(msg){
        var _t = $("#msg").val();
        _t += msg+"\r\n";
        $("#msg").val(_t);
        var scrollTop = $("#msg")[0].scrollHeight;
        $("#msg").scrollTop(scrollTop);
    }
</script>
<body>
<h2>大视频分片上传至oss</h2>
<p>线程数：
    <select id="threadCount" style="height:28px;">
        <option value="1">1</option>
        <option value="2" selected="selected">2</option>
        <option value="3">3</option>
        <option value="5">5</option>
        <option value="10">10</option>
    </select>
</p>
<!--<input type="file" id="x" onchange="afterselect();">-->
<style>
    .file {
        position: relative;
        display: inline-block;
        background: #D0EEFF;
        border: 1px solid #99D3F5;
        border-radius: 4px;
        padding: 4px 12px;
        overflow: hidden;
        color: #1E88C7;
        text-decoration: none;
        text-indent: 0;
        line-height: 20px;
    }
    .file input {
        position: absolute;
        font-size: 100px;
        right: 0;
        top: 0;
        opacity: 0;
    }
    .file:hover {
        background: #AADFFD;
        border-color: #78C3F3;
        color: #004974;
        text-decoration: none;
    }
</style>



<a href="javascript:;" class="file">请选择视频
    <input type="file" id="x" onchange="afterselect();">
</a>



<p></p>
<textarea id="msg" style="width:10%;height:100px;overflow-y:auto;"></textarea>
<p></p>
<div id="percent-bg">
    <span id="percent"></span>
    <span id="percent_num">0%</span>
</div>
</body>
</html>